home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / vim / src / cmdcmds.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  12KB  |  542 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Read the file "credits.txt" for a list of people who contributed.
  6.  * Read the file "uganda.txt" for copying and usage conditions.
  7.  */
  8.  
  9. /*
  10.  * cmdcmds.c: functions for command line commands
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16. #include "param.h"
  17.  
  18. #if defined(LATTICE) || defined(NT)
  19. # define mktemp(a)    tmpnam(a)
  20. #endif
  21.  
  22. extern char        *mktemp __ARGS((char *));
  23.  
  24. /*
  25.  * align text:
  26.  * type = -1  left aligned
  27.  * type = 0   centered
  28.  * type = 1   right aligned
  29.  */
  30.     void
  31. do_align(start, end, width, type)
  32.     linenr_t    start;
  33.     linenr_t    end;
  34.     int            width;
  35.     int            type;
  36. {
  37.     FPOS    pos;
  38.     int        len;
  39.     int        indent = 0;
  40.  
  41.     pos = curwin->w_cursor;
  42.     if (type == -1)        /* left align: width is used for new indent */
  43.     {
  44.         if (width >= 0)
  45.             indent = width;
  46.     }
  47.     else
  48.     {
  49.         /*
  50.          * if 'textwidth' set, use it
  51.          * else if 'wrapmargin' set, use it
  52.          * if invalid value, use 80
  53.          */
  54.         if (width <= 0)
  55.             width = curbuf->b_p_tw;
  56.         if (width == 0 && curbuf->b_p_wm > 0)
  57.             width = Columns - curbuf->b_p_wm;
  58.         if (width <= 0)
  59.             width = 80;
  60.     }
  61.  
  62.     if (!u_save((linenr_t)(start - 1), (linenr_t)(end + 1)))
  63.         return;
  64.     for (curwin->w_cursor.lnum = start; curwin->w_cursor.lnum <= end; ++curwin->w_cursor.lnum)
  65.     {
  66.         set_indent(indent, TRUE);                /* remove existing indent */
  67.         if (type == -1)                            /* left align */
  68.             continue;
  69.         len = strsize(ml_get(curwin->w_cursor.lnum));        /* get line lenght */
  70.         if (len < width)
  71.             switch (type)
  72.             {
  73.             case 0:        set_indent((width - len) / 2, FALSE);    /* center */
  74.                         break;
  75.             case 1:        set_indent(width - len, FALSE);            /* right */
  76.                         break;
  77.             }
  78.     }
  79.     curwin->w_cursor = pos;
  80.     beginline(TRUE);
  81.     updateScreen(NOT_VALID);
  82. }
  83.  
  84. /*
  85.  * :move command - move lines line1-line2 to line n
  86.  *
  87.  * return FAIL for failure, OK otherwise
  88.  */
  89.     int
  90. do_move(line1, line2, n)
  91.     linenr_t    line1;
  92.     linenr_t    line2;
  93.     linenr_t    n;
  94. {
  95.     char_u        *q;
  96.     int            has_mark;
  97.  
  98.     if (n >= line1 && n < line2 && line2 > line1)
  99.     {
  100.         EMSG("Move lines into themselves");
  101.         return FAIL;
  102.     }
  103.  
  104.     /*
  105.      * adjust line marks (global marks done below)
  106.      * if the lines are moved down, the marks in the moved lines
  107.      * move down and the marks in the lines between the old and
  108.      * new position move up.
  109.      * If the lines are moved up it is just the other way round
  110.      */
  111.     if (n >= line2)            /* move down */
  112.     {
  113.         mark_adjust(line1, line2, n - line2);
  114.         mark_adjust(line2 + 1, n,  -(line2 - line1 + 1));
  115.     }
  116.     else                    /* move up */
  117.     {
  118.         mark_adjust(line1, line2, -(line1 - n - 1));
  119.         mark_adjust(n + 1, line1 - 1, line2 - line1 + 1);
  120.     }
  121.  
  122.     if (n >= line1)
  123.     {
  124.         --n;
  125.         curwin->w_cursor.lnum = n - (line2 - line1) + 1;
  126.     }
  127.     else
  128.         curwin->w_cursor.lnum = n + 1;
  129.     while (line1 <= line2)
  130.     {
  131.             /* this undo is not efficient, but it works */
  132.         u_save(line1 - 1, line1 + 1);
  133.         q = strsave(ml_get(line1));
  134.         if (q != NULL)
  135.         {
  136.             /*
  137.              * marks from global command go with the line
  138.              */
  139.             has_mark = ml_has_mark(line1);
  140.             ml_delete(line1);
  141.             u_save(n, n + 1);
  142.             ml_append(n, q, (colnr_t)0, FALSE);
  143.             free(q);
  144.             if (has_mark)
  145.                 ml_setmarked(n + 1);
  146.         }
  147.         if (n < line1)
  148.         {
  149.             ++n;
  150.             ++line1;
  151.         }
  152.         else
  153.             --line2;
  154.     }
  155.     CHANGED;
  156.     return OK;
  157. }
  158.  
  159. /*
  160.  * :copy command - copy lines line1-line2 to line n
  161.  */
  162.     void
  163. do_copy(line1, line2, n)
  164.     linenr_t    line1;
  165.     linenr_t    line2;
  166.     linenr_t    n;
  167. {
  168.     linenr_t        lnum;
  169.     char_u            *p;
  170.  
  171.     mark_adjust(n + 1, MAXLNUM, line2 - line1 + 1);
  172.  
  173.     /*
  174.      * there are three situations:
  175.      * 1. destination is above line1
  176.      * 2. destination is between line1 and line2
  177.      * 3. destination is below line2
  178.      *
  179.      * n = destination (when starting)
  180.      * curwin->w_cursor.lnum = destination (while copying)
  181.      * line1 = start of source (while copying)
  182.      * line2 = end of source (while copying)
  183.      */
  184.     u_save(n, n + 1);
  185.     curwin->w_cursor.lnum = n;
  186.     lnum = line2 - line1 + 1;
  187.     while (line1 <= line2)
  188.     {
  189.         /* need to use strsave() because the line will be unlocked
  190.             within ml_append */
  191.         p = strsave(ml_get(line1));
  192.         if (p != NULL)
  193.         {
  194.             ml_append(curwin->w_cursor.lnum, p, (colnr_t)0, FALSE);
  195.             free(p);
  196.         }
  197.                 /* situation 2: skip already copied lines */
  198.         if (line1 == n)
  199.             line1 = curwin->w_cursor.lnum;
  200.         ++line1;
  201.         if (curwin->w_cursor.lnum < line1)
  202.             ++line1;
  203.         if (curwin->w_cursor.lnum < line2)
  204.             ++line2;
  205.         ++curwin->w_cursor.lnum;
  206.     }
  207.     CHANGED;
  208.     msgmore((long)lnum);
  209. }
  210.  
  211. /*
  212.  * handle the :! command.
  213.  * We replace the extra bangs by the previously entered command and remember
  214.  * the command.
  215.  */
  216.     void
  217. dobang(addr_count, line1, line2, forceit, arg)
  218.     int            addr_count;
  219.     linenr_t    line1, line2;
  220.     int            forceit;
  221.     char_u        *arg;
  222. {
  223.     static    char_u    *prevcmd = NULL;        /* the previous command */
  224.     char_u            *t;
  225.     char_u            *trailarg;
  226.     int             len;
  227.  
  228.     /*
  229.      * Disallow shell commands from .exrc and .vimrc in current directory for
  230.      * security reasons.
  231.      */
  232.     if (secure)
  233.     {
  234.         secure = 2;
  235.         emsg(e_curdir);
  236.         return;
  237.     }
  238.     len = STRLEN(arg) + 1;
  239.  
  240.     autowrite_all();
  241.     /*
  242.      * try to find an embedded bang, like in :!<cmd> ! [args]
  243.      * (:!! is indicated by the 'forceit' variable)
  244.      */
  245.     trailarg = arg;
  246.     skiptospace(&trailarg);
  247.     skipspace(&trailarg);
  248.     if (*trailarg == '!')
  249.         *trailarg++ = NUL;
  250.     else
  251.         trailarg = NULL;
  252.  
  253.     if (forceit || trailarg != NULL)            /* use the previous command */
  254.     {
  255.         if (prevcmd == NULL)
  256.         {
  257.             emsg(e_noprev);
  258.             return;
  259.         }
  260.         len += STRLEN(prevcmd) * (trailarg != NULL && forceit ? 2 : 1);
  261.     }
  262.  
  263.     if (len > CMDBUFFSIZE)
  264.     {
  265.         emsg(e_toolong);
  266.         return;
  267.     }
  268.     if ((t = alloc(len)) == NULL)
  269.         return;
  270.     *t = NUL;
  271.     if (forceit)
  272.         STRCPY(t, prevcmd);
  273.     STRCAT(t, arg);
  274.     if (trailarg != NULL)
  275.     {
  276.         STRCAT(t, prevcmd);
  277.         STRCAT(t, trailarg);
  278.     }
  279.     free(prevcmd);
  280.     prevcmd = t;
  281.  
  282.     if (bangredo)            /* put cmd in redo buffer for ! command */
  283.     {
  284.         AppendToRedobuff(prevcmd);
  285.         AppendToRedobuff((char_u *)"\n");
  286.         bangredo = FALSE;
  287.     }
  288.         /* echo the command */
  289.     msg_start();
  290.     msg_outchar(':');
  291.     if (addr_count)                        /* :range! */
  292.     {
  293.         msg_outnum((long)line1);
  294.         msg_outchar(',');
  295.         msg_outnum((long)line2);
  296.     }
  297.     msg_outchar('!');
  298.     msg_outtrans(prevcmd, -1);
  299.     msg_ceol();
  300.  
  301.     if (addr_count == 0)                /* :! */
  302.         doshell(prevcmd); 
  303.     else                                /* :range! */
  304.         dofilter(line1, line2, prevcmd, TRUE, TRUE);
  305. }
  306.  
  307. /*
  308.  * call a shell to execute a command
  309.  */
  310.     void
  311. doshell(cmd)
  312.     char_u    *cmd;
  313. {
  314.     BUF        *buf;
  315.  
  316.     /*
  317.      * Disallow shell commands from .exrc and .vimrc in current directory for
  318.      * security reasons.
  319.      */
  320.     if (secure)
  321.     {
  322.         secure = 2;
  323.         emsg(e_curdir);
  324.         msg_end();
  325.         return;
  326.     }
  327.     stoptermcap();
  328.     msg_outchar('\n');                    /* may shift screen one line up */
  329.  
  330.         /* warning message before calling the shell */
  331.     if (p_warn)
  332.         for (buf = firstbuf; buf; buf = buf->b_next)
  333.             if (buf->b_changed)
  334.             {
  335.                 msg_outstr((char_u *)"[No write since last change]\n");
  336.                 break;
  337.             }
  338.  
  339.     windgoto((int)Rows - 1, 0);
  340.     cursor_on();
  341.     (void)call_shell(cmd, 0, TRUE);
  342.  
  343. #ifdef AMIGA
  344.     wait_return(term_console ? -1 : TRUE);        /* see below */
  345. #else
  346.     wait_return(TRUE);                /* includes starttermcap() */
  347. #endif
  348.  
  349.     /*
  350.      * In an Amiga window redrawing is caused by asking the window size.
  351.      * If we got an interrupt this will not work. The chance that the window
  352.      * size is wrong is very small, but we need to redraw the screen.
  353.      * Don't do this if ':' hit in wait_return().
  354.      * THIS IS UGLY but it save an extra redraw.
  355.      */
  356. #ifdef AMIGA
  357.     if (skip_redraw)                /* ':' hit in wait_return() */
  358.         must_redraw = CLEAR;
  359.     else if (term_console)
  360.     {
  361.         OUTSTR("\033[0 q");         /* get window size */
  362.         if (got_int)
  363.             must_redraw = CLEAR;    /* if got_int is TRUE we have to redraw */
  364.         else
  365.             must_redraw = 0;        /* no extra redraw needed */
  366.     }
  367. #endif /* AMIGA */
  368. }
  369.  
  370. /*
  371.  * dofilter: filter lines through a command given by the user
  372.  *
  373.  * We use temp files and the call_shell() routine here. This would normally
  374.  * be done using pipes on a UNIX machine, but this is more portable to
  375.  * the machines we usually run on. The call_shell() routine needs to be able
  376.  * to deal with redirection somehow, and should handle things like looking
  377.  * at the PATH env. variable, and adding reasonable extensions to the
  378.  * command name given by the user. All reasonable versions of call_shell()
  379.  * do this.
  380.  * We use input redirection if do_in is TRUE.
  381.  * We use output redirection if do_out is TRUE.
  382.  */
  383.     void
  384. dofilter(line1, line2, buff, do_in, do_out)
  385.     linenr_t    line1, line2;
  386.     char_u        *buff;
  387.     int            do_in, do_out;
  388. {
  389. #ifdef LATTICE
  390.     char_u        itmp[L_tmpnam];        /* use tmpnam() */
  391.     char_u        otmp[L_tmpnam];
  392. #else
  393.     char_u        itmp[TMPNAMELEN];
  394.     char_u        otmp[TMPNAMELEN];
  395. #endif
  396.     linenr_t     linecount;
  397.  
  398.     /*
  399.      * Disallow shell commands from .exrc and .vimrc in current directory for
  400.      * security reasons.
  401.      */
  402.     if (secure)
  403.     {
  404.         secure = 2;
  405.         emsg(e_curdir);
  406.         return;
  407.     }
  408.     if (*buff == NUL)        /* no filter command */
  409.         return;
  410.     linecount = line2 - line1 + 1;
  411.     curwin->w_cursor.lnum = line1;
  412.     curwin->w_cursor.col = 0;
  413.     /* cursupdate(); */
  414.  
  415.     /*
  416.      * 1. Form temp file names
  417.      * 2. Write the lines to a temp file
  418.      * 3. Run the filter command on the temp file
  419.      * 4. Read the output of the command into the buffer
  420.      * 5. Delete the original lines to be filtered
  421.      * 6. Remove the temp files
  422.      */
  423.  
  424. #ifndef LATTICE
  425.     /* for lattice we use tmpnam(), which will make its own name */
  426.     STRCPY(itmp, TMPNAME1);
  427.     STRCPY(otmp, TMPNAME2);
  428. #endif
  429.  
  430.     if ((do_in && *mktemp((char *)itmp) == NUL) || (do_out && *mktemp((char *)otmp) == NUL))
  431.     {
  432.         emsg(e_notmp);
  433.         return;
  434.     }
  435.  
  436. /*
  437.  * ! command will be overwritten by next mesages
  438.  * This is a trade off between showing the command and not scrolling the
  439.  * text one line up (problem on slow terminals).
  440.  */
  441.     must_redraw = CLEAR;        /* screen has been shifted up one line */
  442.     ++no_wait_return;            /* don't call wait_return() while busy */
  443.     if (do_in && buf_write(curbuf, itmp, NULL, line1, line2, FALSE, 0, FALSE) == FAIL)
  444.     {
  445.         msg_outchar('\n');                    /* keep message from writeit() */
  446.         --no_wait_return;
  447.         (void)emsg2(e_notcreate, itmp);        /* will call wait_return */
  448.         return;
  449.     }
  450.     if (!do_out)
  451.         outchar('\n');
  452.  
  453. #if defined(UNIX) && !defined(ARCHIE)
  454. /*
  455.  * put braces around the command (for concatenated commands)
  456.  */
  457.      sprintf((char *)IObuff, "(%s)", (char *)buff);
  458.     if (do_in)
  459.     {
  460.         STRCAT(IObuff, " < ");
  461.         STRCAT(IObuff, itmp);
  462.     }
  463.     if (do_out)
  464.     {
  465.         STRCAT(IObuff, " > ");
  466.         STRCAT(IObuff, otmp);
  467.     }
  468. #else
  469. /*
  470.  * for shells that don't understand braces around commands, at least allow
  471.  * the use of commands in a pipe.
  472.  */
  473.     STRCPY(IObuff, buff);
  474.     if (do_in)
  475.     {
  476.         char_u        *p;
  477.     /*
  478.      * If there is a pipe, we have to put the '<' in front of it
  479.      */
  480.         p = STRCHR(IObuff, '|');
  481.         if (p)
  482.             *p = NUL;
  483.         STRCAT(IObuff, " < ");
  484.         STRCAT(IObuff, itmp);
  485.         p = STRCHR(buff, '|');
  486.         if (p)
  487.             STRCAT(IObuff, p);
  488.     }
  489.     if (do_out)
  490.     {
  491.         STRCAT(IObuff, " > ");
  492.         STRCAT(IObuff, otmp);
  493.     }
  494. #endif
  495.  
  496.     windgoto((int)Rows - 1, 0);
  497.     cursor_on();
  498.             /* errors are ignored, so you can see the error
  499.                messages from the command; use 'u' to fix the text */
  500.     (void)call_shell(IObuff, 1, FALSE);
  501.  
  502.     if (do_out)
  503.     {
  504.         if (!u_save((linenr_t)(line2), (linenr_t)(line2 + 1)))
  505.         {
  506.             linecount = 0;
  507.             goto error;
  508.         }
  509.         if (readfile(otmp, NULL, line2, FALSE, (linenr_t)0, MAXLNUM) == FAIL)
  510.         {
  511.             outchar('\n');
  512.             emsg2(e_notread, otmp);
  513.             linecount = 0;
  514.             goto error;
  515.         }
  516.  
  517.         if (do_in)
  518.         {
  519.             curwin->w_cursor.lnum = line1;
  520.             dellines(linecount, TRUE, TRUE);
  521.         }
  522.         --no_wait_return;
  523.     }
  524.     else
  525.     {
  526. error:
  527.         --no_wait_return;
  528.         wait_return(FALSE);
  529.     }
  530.     updateScreen(CLEAR);        /* do this before messages below */
  531.  
  532.     if (linecount > p_report)
  533.     {
  534.         if (!do_in && do_out)
  535.             msgmore(linecount);
  536.         else
  537.             smsg((char_u *)"%ld lines filtered", (long)linecount);
  538.     }
  539.     remove((char *)itmp);
  540.     remove((char *)otmp);
  541. }
  542.